using PropertyChanged;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using DotNet.Utilities.ConsoleHelper;
using WPFPractice.Models;
using WPFTemplateLib.UserControls;
using WPFTemplateLib.WpfHelpers;
using System.Windows.Media;
using System.Windows.Shapes;
using CommunityToolkit.Mvvm.Messaging;
using WPFPractice.Messages;
using Point = System.Drawing.Point;

namespace WPFPractice.Windows
{
    /// <summary>
    /// WinBatchSetText.xaml 的交互逻辑
    /// </summary>
    public partial class WinBatchSetText : Window
    {
        public WinBatchSetText()
        {
            InitializeComponent();
            DataContext = new BatchSetTexViewModel();
        }

        #region 路由事件

        public static readonly RoutedEvent RangeSelectedEvent = EventManager.RegisterRoutedEvent("RangeSelected",
            RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(WinBatchSetText));
        /// <summary>
        /// [路由事件]范围选择完成
        /// </summary>
        public event RoutedEventHandler RangeSelected
        {
            add => AddHandler(RangeSelectedEvent, value);
            remove => RemoveHandler(RangeSelectedEvent, value);
        }
        /// <summary>
        /// 路由事件 范围选择完成 的触发方法
        /// </summary>
        /// <param name="originalSource">此参数会传递到事件参数的 OriginalSource 属性中</param>
        private void RaiseRangeSelectedEvent(object originalSource = null)
        {
            RaiseEvent(new RoutedEventArgs(RangeSelectedEvent, originalSource));
        }

        #endregion

        #region 拖动时的线框

        /// <summary>
        /// 范围选择时的起始位置
        /// </summary>
        private System.Drawing.Point _beginPosition;

        /// <summary>
        /// 鼠标是否按下
        /// </summary>
        private bool _isMouseDown = false;

        /// <summary>
        /// 鼠标按下的位置
        /// </summary>
        private System.Windows.Point _mouseDownPosition;

        /// <summary>
        /// 拖动要显示的矩形
        /// </summary>
        private Rectangle _rectangle;

        /// <summary>
        /// 文本框鼠标按下的隧道事件
        /// （拦截鼠标事件、记录起始位置、初始化矩形）
        /// </summary>
        private void TextBox_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true; //拦截鼠标事件,避免焦点始终在起点;

            var tb = sender as TextBox;
            if (tb!.DataContext is BatchSetItem item)
            {
                _beginPosition = item.Position;
            }

            ShowDrag(e, tb);
        }

        /// <summary>
        /// 准备展示拖动范围的矩形
        /// </summary>
        /// <param name="e">鼠标事件</param>
        /// <param name="control">Grid内部对象</param>
        private void ShowDrag(MouseButtonEventArgs e, Control control)
        {
            //需要在外层有个 Grid 。
            Grid grid = control.TryFindParent<Grid>();
            if (grid == null) return;

            //初始化鼠标选择范围的矩形;
            if (_rectangle == null)
            {
                //方法一：后台创建矩形,并添加到 Grid 内部末尾;
                _rectangle = new Rectangle()
                {
                    VerticalAlignment = VerticalAlignment.Top,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Stroke = new SolidColorBrush(Colors.Coral),
                };
                grid.Children.Add(_rectangle);
                grid.InvalidateArrange(); //更新布局，否则矩形不会盖在上面；

                //方法二：前台在 Grid 的内部的末尾放置矩形(名称为"rect")，后台直接寻找;
                //_rectangle = grid.FindChild<Rectangle>("rect");
                //if (_rectangle == null)
                //{
                //    return;
                //}
            }

            _isMouseDown = true;
            _mouseDownPosition = e.GetPosition(grid);

            //边距加 1 是为了不让线框和鼠标挨着，避免影响后续事件；
            _rectangle.Margin = new Thickness(_mouseDownPosition.X + 1, _mouseDownPosition.Y + 1, 0, 0);
            _rectangle.Width = 5;
            _rectangle.Height = 5;
            _rectangle.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// Grid 中的鼠标移动的隧道事件
        /// （实时改变矩形）
        /// </summary>
        private void Grid_OnPreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (!_isMouseDown) return;

            try
            {
                var grid = sender as Grid;
                if (grid == null) return;

                var pos = e.GetPosition(grid);
                double marginX = _mouseDownPosition.X;
                double marginY = _mouseDownPosition.Y;
                double width, height;

                double distanceX = pos.X - _mouseDownPosition.X;
                if (distanceX < 0)
                {
                    distanceX = Math.Abs(distanceX);
                    marginX = _mouseDownPosition.X - distanceX + 1;
                    width = distanceX;
                }
                else
                {
                    width = distanceX - 1; //减 1 是为了不让线框和鼠标挨着，避免影响后续事件；
                }

                double distanceY = pos.Y - _mouseDownPosition.Y;
                if (distanceY < 0)
                {
                    distanceY = Math.Abs(distanceY);
                    marginY = _mouseDownPosition.Y - distanceY + 1;
                    height = distanceY;
                }
                else
                {
                    height = distanceY - 1; //减 1 是为了不让线框和鼠标挨着，避免影响后续事件；
                }

                _rectangle.Margin = new Thickness(marginX, marginY, 0, 0);
                //由于有一些减 1 操作，此处需避免小范围拖动时宽高变为负数的问题;
                _rectangle.Width = width > 0 ? width : 0;
                _rectangle.Height = height > 0 ? height : 0;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        /// <summary>
        /// Grid 中的鼠标抬起隧道事件（隐藏矩形）
        /// </summary>
        private void Grid_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            var grid = sender as Grid;
            if (grid == null) return;

            _isMouseDown = false;
            _rectangle.Visibility = Visibility.Collapsed;
        }

        #endregion

        /// <summary>
        /// 文本框的鼠标抬起隧道事件
        /// </summary>
        private void TextBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            var tb = sender as TextBox;
            if (tb == null) return;

            BatchSetItem lastItem = tb.DataContext as BatchSetItem;
            if (lastItem == null) return;

            var (beginPosition, endPosition) = AdjustRangePosition(_beginPosition, lastItem.Position);

            var message = new BatchSetTextBoxMessage()
            {
                PositionBegin = beginPosition,
                PositionEnd = endPosition,
                //Text = text,
            };
            //WeakReferenceMessenger.Default.Send(message, nameof(BatchSetTextBoxMessage));

            //RaiseEvent(new RoutedEventArgs(RangeSelectedEvent));
            RaiseRangeSelectedEvent(message);
        }

        /// <summary>
        /// 调整选取范围表示形式为左上角到右下角
        /// </summary>
        /// <param name="originBeginPosition">原始的开始位置</param>
        /// <param name="originEndPosition">原始的结束位置</param>
        /// <returns>统一的起止位置（左上角到右下角）</returns>
        private (Point beginPosition, Point endPosition) AdjustRangePosition(Point originBeginPosition, Point originEndPosition)
        {
            Point beginPosition = originBeginPosition;
            Point endPosition = originEndPosition;

            //起点在左下角;
            if (beginPosition.X > endPosition.X && beginPosition.Y < endPosition.Y)
            {
                var temp = beginPosition;
                beginPosition = new Point(endPosition.X, beginPosition.Y);
                endPosition = new Point(temp.X, endPosition.Y);
            }

            //起点在右下角;
            if (beginPosition.X >= endPosition.X && beginPosition.Y >= endPosition.Y)
            {
                (beginPosition, endPosition) = (endPosition, beginPosition);
            }

            //起点在右上角;
            if (beginPosition.X < endPosition.X && beginPosition.Y > endPosition.Y)
            {
                var temp = beginPosition;
                beginPosition = new Point(beginPosition.X, endPosition.Y);
                endPosition = new Point(endPosition.X, temp.Y);
            }

            return (beginPosition, endPosition);
        }

        //private void WinBatchSetText_OnRangeSelected(object sender, RoutedEventArgs e)
        //{
        //}
    }

    [AddINotifyPropertyChangedInterface]
    public class BatchSetTexViewModel : BindableBase
    {
        #region 绑定

        public ObservableCollection<BatchSetItem> Datas { get; set; }

        /// <summary>
        /// 弹窗VM;
        /// </summary>
        public ConfirmBoxViewModel DialogVm { get; set; } = new ConfirmBoxViewModel();

        #endregion

        #region 命令

        /// <summary>
        /// [命令]批量设置文本框值（在鼠标抬起时被调用）
        /// </summary>
        public RelayCommand<BatchSetTextBoxMessage> BatchSetTextCmd { get; set; }

        #endregion

        public BatchSetTexViewModel()
        {
            SetCommandMethod();

            InitValue();

            Console.SetOut(new ConsoleWriter(s =>
            {
                ShowInfoUc(s);
            }));
        }

        /// <summary>
        /// 数据初始化
        /// </summary>
        private void InitValue()
        {
            ShowInfoUc(@"演示 批量设置文本框的值，相同的值相同的背景色，鼠标拖动线框");

            List<BatchSetItem> list = new int[64].Select(x => new BatchSetItem()).ToList();
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    list[i * 8 + j].Position = new Point(i, j);
                }
            }
            Datas = new ObservableCollection<BatchSetItem>(list);
        }

        /// <summary>
        /// 命令方法赋值(在构造函数中调用)
        /// </summary>
        private void SetCommandMethod()
        {
            BatchSetTextCmd = new RelayCommand<BatchSetTextBoxMessage>(OnBatchSetTextCmd);
        }

        private async Task OnBatchSetTextCmd(BatchSetTextBoxMessage message)
        {
            var inputVM = new InputModel()
            {
                IsOnlyOneColumn = true,
                TitleLeft = "修改后请点击确定按钮",
                //IsShowTitle = false,
                IsShowBottom = false,
            };

            inputVM.LeftContent = new StackPanel
            {
                Children =
                {
                    GetControl.GetLineInput("请输入：", nameof(inputVM.Text)),
                },
                HorizontalAlignment = HorizontalAlignment.Center,
            };

            //DialogVm.ConfirmDialogTimeOut = 600;
            //DialogVm.CustomContentHorizontalAlignment = HorizontalAlignment.Stretch;
            DialogVm.CustomContent = new UC_CustomInfo()
            {
                DataContext = inputVM,
            };

            await ConfirmBoxHelper.ShowConfirm(DialogVm, "", async () =>
            {
                Console.WriteLine($"输入的信息：{inputVM.Text}");
                BatchSetTextBoxValue(inputVM.Text, message);
            }, msg => { Console.WriteLine(msg); }, isShowText: false);
        }

        /// <summary>
        /// 批量设置文本框内容
        /// </summary>
        /// <param name="text">内容</param>
        /// <param name="message">消息</param>
        private void BatchSetTextBoxValue(string text, BatchSetTextBoxMessage message)
        {
            try
            {
                var cellsToChange = Datas.Where(x =>
                    x.Position.X >= message.PositionBegin.X
                    && x.Position.X <= message.PositionEnd.X
                    && x.Position.Y >= message.PositionBegin.Y
                    && x.Position.Y <= message.PositionEnd.Y).ToList();

                var coloredItem = Datas.FirstOrDefault(x => x.Text + "" == text);
                Color color;
                if (coloredItem != null)
                {
                    color = coloredItem.BackgroundColor;
                }
                else
                {
                    color = Color.FromRgb(
                        (byte)Random.Shared.Next(100, 255),
                        (byte)Random.Shared.Next(100, 255),
                        (byte)Random.Shared.Next(100, 255));
                }

                foreach (var cell in cellsToChange)
                {
                    //cell.Text = message.Text;
                    cell.Text = text;
                    cell.BackgroundColor = color;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                MessageBox.Show($"{ex.Message}");
            }
        }
    }
}
